﻿using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Runtime.InteropServices;
using System.Security.Policy;
using System.Text;
using System.Xml;
using Microsoft.SqlServer.Management.Smo;
using Microsoft.SqlServer.Management.UI.VSIntegration.ObjectExplorer;
using System.Windows.Forms;
using SsmsAddin.Properties;

namespace SsmsAddin
{
    public class MenuItem : ToolsMenuItemBase, IWinformsMenuHandler
    {
        public static XmlDocument _doc;
        private static readonly bool[] ApplyArray = new bool[4];
        public const int TV_FIRST = 0x1100;
        public const int TVC_BYKEYBOARD = 2;
        public const int TVC_BYMOUSE = 1;
        public const int TVC_UNKNOWN = 0;
        public const int TVE_COLLAPSE = 1;
        public const int TVE_EXPAND = 2;
        public const int TVGN_CARET = 9;
        private const int TVGN_CHILD = 4;
        public const int TVGN_FIRSTVISIBLE = 5;
        public const int TVGN_NEXT = 1;
        public const int TVGN_NEXTVISIBLE = 6;
        private const int TVGN_PARENT = 3;
        public const int TVGN_PREVIOUS = 2;
        public const int TVGN_PREVIOUSVISIBLE = 7;
        private const int TVGN_ROOT = 0;
        public const int TVHT_ONITEM = 70;
        public const int TVHT_ONITEMSTATEICON = 0x40;
        public const int TVI_FIRST = -65535;
        public const int TVI_ROOT = -65536;
        public const int TVIF_HANDLE = 0x10;
        public const int TVIF_IMAGE = 2;
        public const int TVIF_SELECTEDIMAGE = 0x20;
        public const int TVIF_STATE = 8;
        public const int TVIF_TEXT = 1;
        public const int TVIS_EXPANDED = 0x20;
        public const int TVIS_EXPANDEDONCE = 0x40;
        public const int TVIS_SELECTED = 2;
        public const int TVIS_STATEIMAGEMASK = 0xf000;
        public const int TVM_DELETEITEM = 0x1101;
        public static readonly int TVM_EDITLABEL;
        public const int TVM_EDITLABELA = 0x110e;
        public const int TVM_EDITLABELW = 0x1141;
        public const int TVM_ENDEDITLABELNOW = 0x1116;
        public const int TVM_ENSUREVISIBLE = 0x1114;
        public const int TVM_EXPAND = 0x1102;
        public const int TVM_GETEDITCONTROL = 0x110f;
        public const int TVM_GETINDENT = 0x1106;
        public static readonly int TVM_GETISEARCHSTRING;
        public const int TVM_GETISEARCHSTRINGA = 0x1117;
        public const int TVM_GETISEARCHSTRINGW = 0x1140;
        public static readonly int TVM_GETITEM;
        public const int TVM_GETITEMA = 0x110c;
        public const int TVM_GETITEMHEIGHT = 0x111c;
        public const int TVM_GETITEMRECT = 0x1104;
        public const int TVM_GETITEMW = 0x113e;
        public const int TVM_GETNEXTITEM = 0x110a;
        public const int TVM_GETVISIBLECOUNT = 0x1110;
        public const int TVM_HITTEST = 0x1111;
        public static readonly int TVM_INSERTITEM;
        public const int TVM_INSERTITEMA = 0x1100;
        public const int TVM_INSERTITEMW = 0x1132;
        public const int TVM_SELECTITEM = 0x110b;
        public const int TVM_SETBKCOLOR = 0x111d;
        public const int TVM_SETIMAGELIST = 0x1109;
        public const int TVM_SETINDENT = 0x1107;
        public static readonly int TVM_SETITEM;
        public const int TVM_SETITEMA = 0x110d;
        public const int TVM_SETITEMHEIGHT = 0x111b;
        public const int TVM_SETITEMW = 0x113f;
        public const int TVM_SETTEXTCOLOR = 0x111e;
        public static readonly int TVN_BEGINDRAG;
        public const int TVN_BEGINDRAGA = -407;
        public const int TVN_BEGINDRAGW = -456;
        public static readonly int TVN_BEGINLABELEDIT;
        public const int TVN_BEGINLABELEDITA = -410;
        public const int TVN_BEGINLABELEDITW = -459;
        public static readonly int TVN_BEGINRDRAG;
        public const int TVN_BEGINRDRAGA = -408;
        public const int TVN_BEGINRDRAGW = -457;
        public static readonly int TVN_ENDLABELEDIT;
        public const int TVN_ENDLABELEDITA = -411;
        public const int TVN_ENDLABELEDITW = -460;
        public static readonly int TVN_GETDISPINFO;
        public const int TVN_GETDISPINFOA = -403;
        public const int TVN_GETDISPINFOW = -452;
        public static readonly int TVN_ITEMEXPANDED;
        public const int TVN_ITEMEXPANDEDA = -406;
        public const int TVN_ITEMEXPANDEDW = -455;
        public static readonly int TVN_ITEMEXPANDING;
        public const int TVN_ITEMEXPANDINGA = -405;
        public const int TVN_ITEMEXPANDINGW = -454;
        public static readonly int TVN_SELCHANGED;
        public const int TVN_SELCHANGEDA = -402;
        public const int TVN_SELCHANGEDW = -451;
        public static readonly int TVN_SELCHANGING;
        public const int TVN_SELCHANGINGA = -401;
        public const int TVN_SELCHANGINGW = -450;
        public static readonly int TVN_SETDISPINFO;
        public const int TVN_SETDISPINFOA = -404;
        public const int TVN_SETDISPINFOW = -453;
        public const int TVS_CHECKBOXES = 0x100;
        public const int TVS_EDITLABELS = 8;
        public const int TVS_FULLROWSELECT = 0x1000;
        public const int TVS_HASBUTTONS = 1;
        public const int TVS_HASLINES = 2;
        public const int TVS_LINESATROOT = 4;
        public const int TVS_RTLREADING = 0x40;
        public const int TVS_SHOWSELALWAYS = 0x20;
        public const int TVS_TRACKSELECT = 0x200;
        public const int TVSIL_STATE = 2;

        public MenuItem()
        {
            base.Text = "Script Data as INSERT";
        }

        public override object Clone()
        {
            return new MenuItem();
        }

        [DllImport("kernel32")]
        private static extern bool CloseHandle(IntPtr hObject);
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindow(string className, string windowTitle);
        [DllImport("user32.dll")]
        public static extern IntPtr FindWindowEx(IntPtr handleParent, IntPtr handleChild, string className, string WindowName);
        public ToolStripItem[] GetMenuItems()
        {
            Utils.UpdateObjectExplorerInfo();
            string dbName = Utils._DBNode.dbName;
            ToolStripMenuItem item = new ToolStripMenuItem("SVN [test]");
            ToolStripMenuItem item2 = new ToolStripMenuItem("Open file");
            ToolStripMenuItem item3 = new ToolStripMenuItem("Lock file");
            ToolStripMenuItem item4 = new ToolStripMenuItem("Commit file");
            ToolStripMenuItem item5 = new ToolStripMenuItem("Refresh file");
            ToolStripMenuItem item6 = new ToolStripMenuItem("Log file");
            //ToolStripMenuItem item7 = new ToolStripMenuItem("TEST CHANGE ICON");
            ToolStripMenuItem item8 = new ToolStripMenuItem("Apply script on...");
            string str = this.RunSvnCommand();
            if (str != "")
            {
                item.DropDownItems.Add(string.Format("Locked by {0}", str), Resources.LockIcon.ToBitmap());
                item.DropDownItems.Add(new ToolStripSeparator());
            }
            item2.Tag = true;
            item2.Click += new EventHandler(MenuItem.svn_Open);
            item3.Tag = true;
            item3.Click += new EventHandler(this.svn_Lock);
            item4.Tag = true;
            item4.Click += new EventHandler(this.svn_Commit);
            item5.Tag = true;
            item5.Click += new EventHandler(this.svn_Refresh);
            item6.Tag = true;
            item6.Click += new EventHandler(MenuItem.svn_Log);
            //item7.Tag = true;
            //item7.Click += new EventHandler(MenuItem.svn_test);
            item8.Click += new EventHandler(MenuItem.svn_Apply);
            item.DropDownItems.Add(item3);
            item.DropDownItems.Add(item4);
            item.DropDownItems.Add(item2);
            item.DropDownItems.Add(item5);
            item.DropDownItems.Add(item6);
            //item.DropDownItems.Add(item7);
            return new ToolStripItem[] { item, item8 };
        }

        private static string GetTreeItem_Local(IntPtr hwnd, IntPtr hItem)
        {
            TVITEM pitem = new TVITEM();
            IntPtr p = LocalAlloc(0x40, 0x100);
            pitem.mask = 1;
            pitem.hItem = hItem;
            pitem.cchTextMax = 0x100;
            pitem.pszText = p;
            SendMessage(hwnd, 0x113e, 0, ref pitem);
            string str = Marshal.PtrToStringAuto(pitem.pszText);
            str.ToCharArray();
            LocalFree(p);
            return str;
        }

        [DllImport("user32")]
        private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out int lpwdProcessID);
        private static int INDEXTOSTATEIMAGEMASK(int i)
        {
            return (i << 12);
        }

        private static void InitSVN()
        {
        }

        protected override void Invoke()
        {
        }

        [DllImport("kernel32.dll")]
        public static extern IntPtr LocalAlloc(uint flags, uint cb);
        [DllImport("kernel32.dll")]
        public static extern IntPtr LocalFree(IntPtr p);
        [DllImport("kernel32")]
        private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, int dwProcessId);
        [DllImport("kernel32")]
        private static extern bool ReadProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, IntPtr lpBuffer, int dwSize, IntPtr lpNumberOfBytesRead);
        protected string RunSvnCommand()
        {
            
            var process = new Process
                          {
                              EnableRaisingEvents = false, 
                              StartInfo =
                                  {
                                      CreateNoWindow = true, 
                                      FileName = "svn.exe",
                                      Arguments = string.Format("info {0}.sql", Utils.ConcatUrls(Utils.GetServerSvnPath(), Utils._DBNode.objectName.ToLower())), 
                                      UseShellExecute = false, 
                                      RedirectStandardOutput = true
                                  }
                          };
            process.Start();
            while (!process.StandardOutput.EndOfStream)
            {
                string str2 = process.StandardOutput.ReadLine();
                if (str2.StartsWith("Lock Owner:"))
                {
                    return str2.Substring(11).Trim();
                }
            }
            return "";
        }

        private static IntPtr SearchForSolutionExplorer(IntPtr parent, string caption)
        {
            IntPtr ptr = FindWindowEx(parent, IntPtr.Zero, "GenericPane", caption);
            if (ptr != IntPtr.Zero)
            {
                return ptr;
            }
            for (IntPtr ptr2 = FindWindowEx(parent, IntPtr.Zero, null, null); ptr2 != IntPtr.Zero; ptr2 = FindWindowEx(parent, ptr2, null, null))
            {
                ptr = SearchForSolutionExplorer(ptr2, caption);
                if (ptr != IntPtr.Zero)
                {
                    return ptr;
                }
            }
            return IntPtr.Zero;
        }

        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern int SendMessage(IntPtr hWnd, int msg, int wParam, IntPtr lParam);
        [DllImport("User32.dll", CharSet = CharSet.Auto)]
        public static extern bool SendMessage(IntPtr hWnd, int msg, int wParam, ref TVITEM pitem);
        private static void svn_Apply(object sender, EventArgs e)
        {
        }

        private void svn_Commit(object sender, EventArgs e)
        {
            if (MessageBox.Show("Mettre \x00e0 jour avec la version en base ?", "SVN", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                this.svn_Refresh(sender, e);
            }
            Utils.execSvnCommand(Utils.svnCommand.scCommit);
            Process.Start(Utils._GetFilePath());
        }

        private void svn_Lock(object sender, EventArgs e)
        {
            Utils.execSvnCommand(Utils.svnCommand.scLock);
            if (MessageBox.Show("Mettre \x00e0 jour avec la version en base ?", "SVN", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
            {
                this.svn_Refresh(sender, e);
            }
            Process.Start(Utils._GetFilePath());
        }

        private static void svn_Log(object sender, EventArgs e)
        {
            Utils.execSvnCommand(Utils.svnCommand.scLog);
        }

        private static void svn_Open(object sender, EventArgs e)
        {
            Process.Start(Utils._GetFilePath());
        }

        private void svn_Refresh(object sender, EventArgs e)
        {
            string str4;
            string serverName = Utils._DBNode.serverName;
            string objectName = Utils._DBNode.objectName;
            string dbName = Utils._DBNode.dbName;
            var svr = new Server(serverName);
            var database = svr.Databases[dbName];
            var strings = new StringCollection();
            var objects = new SqlSmoObject[1];
            if (Utils._DBNode.objectType == ObjectType.StoredProcedure.ToString())
            {
                StoredProcedure procedure = database.StoredProcedures[objectName];
                objects[0] = procedure;
            }
            else if (Utils._DBNode.objectType == ObjectType.View.ToString())
            {
                Microsoft.SqlServer.Management.Smo.View view = database.Views[objectName];
                objects[0] = view;
            }
            strings = new Scripter(svr) { Options = { IncludeIfNotExists = false, DriAll = true, Permissions = false } }.Script(objects);
            if (Utils._DBNode.objectType == ObjectType.StoredProcedure.ToString())
            {
                strings.Add("GO");
                strings.Add("GRANT  EXECUTE  ON " + objectName + " TO PUBLIC");
                str4 = string.Format("If Exists(Select name From sysobjects Where name='{0}' And type='P ' And uid = User_id('dbo')) Drop Proc {0}", objectName);
                strings.Insert(0, "GO");
                strings.Insert(0, str4);
            }
            else if (Utils._DBNode.objectType == ObjectType.View.ToString())
            {
                strings.Add("GO");
                strings.Add("GRANT  Select, Insert, Update, Delete ON " + objectName + " TO PUBLIC");
                str4 = string.Format("IF  EXISTS (SELECT * FROM sys.views WHERE object_id = OBJECT_ID(N'{0}')) DROP VIEW {0}", objectName);
                strings.Insert(0, "GO");
                strings.Insert(0, str4);
            }

            try
            {
                TextWriter writer = new StreamWriter(Utils._GetFilePath());
                if (strings != null)
                {
                    var enumerator = strings.GetEnumerator();
                    while (enumerator.MoveNext())
                    {
                        str4 = enumerator.Current.Replace("SET ANSI_NULLS ON", string.Empty).Replace("SET QUOTED_IDENTIFIER ON", string.Empty).Replace("SET ANSI_NULLS OFF", string.Empty).Replace("SET QUOTED_IDENTIFIER OFF", string.Empty);
                        writer.WriteLine(str4);
                    }
                }
                writer.Flush();
                writer.Close();
                writer = null;
            }
            catch (IOException exception)
            {
                MessageBox.Show(exception.ToString());
            }
        }

        //private static void svn_test(object sender, EventArgs e)
        //{
        //    IntPtr hWnd = FindWindowEx(FindWindowEx(FindWindowEx(SearchForSolutionExplorer(FindWindow(null, "Microsoft SQL Server Management Studio"), null), IntPtr.Zero, "GenericPane", null), IntPtr.Zero, "WindowsForms10.Window.8.app.0.33c0d9d", null), IntPtr.Zero, "WindowsForms10.SysTreeView32.app.0.33c0d9d", null);
        //    ImageList list = new ImageList();
        //    Bitmap statusGlyphs = Resources.StatusGlyphs;
        //    list.ImageSize = new Size(8, statusGlyphs.Height);
        //    statusGlyphs.MakeTransparent(statusGlyphs.GetPixel(0, 0));
        //    list.Images.AddStrip(statusGlyphs);
        //    IntPtr lParam = TreeView_GetNextItem(hWnd, IntPtr.Zero, (IntPtr)9);
        //    lParam = (IntPtr)SendMessage(hWnd, 0x110a, 3, lParam);
        //    IntPtr hItem = (IntPtr)SendMessage(hWnd, 0x110a, 4, lParam);
        //    TreeView_SetStateImageList(hWnd, list.Handle);
        //    int imageIndex = 0;
        //    using (SvnClient client = new SvnClient())
        //    {
        //        client.Authentication.DefaultCredentials = new NetworkCredential("", "");
        //        SvnUI.Bind(client, (IWin32Window)null);
        //        SvnStatusArgs args = new SvnStatusArgs
        //        {
        //            Depth = SvnDepth.Empty
        //        };
        //        while (((int)hItem) > 0)
        //        {
        //            string dbName = GlobalSVN._DBNode.dbName;
        //            string str = GetTreeItem_Local(hWnd, hItem);
        //            if (str.StartsWith("dbo."))
        //            {
        //                Collection<SvnStatusEventArgs> collection;
        //                str = str.ToLower().Replace("dbo.", "");
        //                if (!client.GetStatus(GlobalSVN._GetFilePath(), args, out collection))
        //                {
        //                    imageIndex = 7;
        //                }
        //                else if (collection.Count == 0)
        //                {
        //                    imageIndex = 0;
        //                }
        //                else
        //                {
        //                    SvnStatus localContentStatus = collection[0].LocalContentStatus;
        //                    if (localContentStatus != SvnStatus.Added)
        //                    {
        //                        if (localContentStatus == SvnStatus.Modified)
        //                        {
        //                            goto Label_019F;
        //                        }
        //                        goto Label_01A4;
        //                    }
        //                    imageIndex = 13;
        //                }
        //            }
        //            goto Label_01A7;
        //        Label_019F:
        //            imageIndex = 4;
        //            goto Label_01A7;
        //        Label_01A4:
        //            imageIndex = 0;
        //        Label_01A7:
        //            TreeView_SetStateImageIndex(hWnd, hItem, imageIndex);
        //            hItem = (IntPtr)SendMessage(hWnd, 0x110a, 1, hItem);
        //        }
        //    }
        //}

        private static void svnApplyClick(object sender, EventArgs e)
        {
            ToolStripMenuItem item1 = (ToolStripMenuItem)sender;
            item1.Checked ^= ((ToolStripMenuItem)sender).Checked;
            ApplyArray[(int)((ToolStripMenuItem)sender).Tag] = ((ToolStripMenuItem)sender).Checked;
        }

        private static IntPtr TreeView_GetNextItem(IntPtr hWnd, IntPtr hItem, IntPtr flag)
        {
            return (IntPtr)SendMessage(hWnd, 0x110a, (int)flag, hItem);
        }

        private static void TreeView_SetStateImageIndex(IntPtr hwnd, IntPtr hItem, int imageIndex)
        {
            TVITEM pitem = new TVITEM
            {
                hItem = hItem,
                mask = 8,
                stateMask = 0xf000,
                state = INDEXTOSTATEIMAGEMASK(imageIndex)
            };
            SendMessage(hwnd, 0x110d, 0, ref pitem);
        }

        private static void TreeView_SetStateImageList(IntPtr hwnd, IntPtr hImageList)
        {
            SendMessage(hwnd, 0x1109, 2, hImageList);
        }

        [DllImport("kernel32")]
        private static extern IntPtr VirtualAllocEx(IntPtr hProcess, IntPtr lpAddress, int dwSize, uint flAllocationType, uint flProtect);
        [DllImport("kernel32")]
        private static extern bool WriteProcessMemory(IntPtr hProcess, IntPtr lpBaseAddress, ref TVITEM buffer, int dwSize, IntPtr lpNumberOfBytesWritten);

        public enum ObjectType
        {
            StoredProcedure = 1,
            Table = 3,
            View = 2
        }

        [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto, Pack = 1)]
        public struct TVITEM
        {
            public int cChildren;
            public int cchTextMax;
            public IntPtr hItem;
            public int iImage;
            public int iSelectedImage;
            public IntPtr lParam;
            public int mask;
            public IntPtr pszText;
            public int state;
            public int stateMask;
        }
    }


}
